/*
 * Vectrics 
 * Created on Jan 29, 2004
 *
 */
package org.vectrics.imaging.client;

import org.apache.log4j.Logger;
import java.awt.*;
import java.awt.image.*;
import java.io.FileInputStream;
import java.io.IOException;

import javax.swing.JPanel;




/**
 * @author mmoore
 *
 * To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
public class ImagePanel extends JPanel implements ImageObserver {
	//private Image image;
	private Image scaledImage;
	//private Image originalImage;
	private transient static Logger log = Logger.getLogger(ImagePanel.class);
	private int fixedHeight = -1;
	private int fixedWidth = -1;
	private String fileName = null;
	private boolean storeOriginal = false;
	private int scalePercent = 100;
	private int lastRenderedScalePercent = -1;
	private byte imageBytes[] = null;
	private int panelHeight = -1;
	private int panelWidth = -1;

	
	public ImagePanel() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public String getFileName() {
		return(fileName);
	}
	
	public void setScale(int percent) {
		log.info("setScale() - Scale percent changed to " + percent);
		this.scalePercent = percent;
	}
	
	public void showFile(String fileName) {
		this.fileName = fileName;
		if (fileName.endsWith(".eji")) {
			log.debug("Encrypted file passed, decrypting...");	
			imageBytes = EncryptedFileUtils.readEncryptedFile(fileName);
			showBytes();
		}
		else {
			try {
				FileInputStream fileStream = new FileInputStream(fileName);
				try {
					int count = fileStream.available();
					log.debug("showfile() - creating new imageBytes array to hold image data. Size = " + count);
					imageBytes = new byte[count];
					fileStream.read(imageBytes);
					fileStream.close();
				}
				catch (IOException ie) {
					log.error("IOException reading stream", ie);
				}
				showBytes();
				
			}
			catch (IOException ie) {
				log.error("Exception loading file: ", ie);	
			}
		}
	}
	
	
	
	public String getEncryptedFileName(){
		String encFileName = "" + this.fileName.hashCode() + ".eji";
		return(encFileName);
	}
/*	
	public void readEncryptedFile(String fileName) {
		byte inBytes[] = null;
		byte outBytes[] = null;
		try {
			FileInputStream fileStream = new FileInputStream(fileName);
			int count = fileStream.available();
			inBytes = new byte[count];
			outBytes = new byte[count];
			fileStream.read(inBytes);
			fileStream.close();
		}
		catch (FileNotFoundException fe) {
			log.error("readEncryptedFile() - file not found exceptiong for file: " + fileName, fe);
		}
		catch (IOException ie) {
			log.error("IOException reading data from encrypted file: " + fileName);
		}
		
		BlowfishEngine engine = new BlowfishEngine();
		BufferedBlockCipher cipher = new BufferedBlockCipher(engine);
		KeyParameter param = new KeyParameter(Hex.decode("3000000000000000"));
		cipher.init(false, param);
		int len1 = cipher.processBytes(inBytes, 0, inBytes.length, outBytes, 0);

		try
		{
			cipher.doFinal(outBytes, len1);
		}
		catch (CryptoException e)
		{
			log.error("CrytoException saving encrypted file");
		}
		
		log.debug("find number of padding bytes at end");
		int padCount = 0;
		String padCountStr = "";
		for (int i = 0; i < this.PAD_COUNT_SIZE; i++) {
			//int digitByte = outBytes[i];
			//log.debug("digitByte = " + digitByte);
			//padCount += (padCount * 10) + digitByte;
			padCountStr += "" + (int)outBytes[i];
			log.debug("padCountStr = " + padCountStr);
		}
		padCount = Integer.parseInt(padCountStr);
		log.debug("Reading encrypted file - Pad Count = " + padCount);
		
		int dataLength = outBytes.length - (this.PAD_COUNT_SIZE + padCount);
		
		log.debug("Creating array for bytes[] - the raw data held in this class for the image.  Size = " + dataLength);
		imageBytes = new byte[dataLength];
		for (int i = 0; i < dataLength; i++) {
			imageBytes[i] = outBytes[i + this.PAD_COUNT_SIZE];
		}
		
		log.debug("After encryption - imageBytes.size = " + imageBytes.length);
		//logBytes("Decrypted bytes (image bytes)", imageBytes);

		
	}
*/	
	
	
	/**
	* Convenience method to convert an int to a hex char.
	*
	* @param i the int to convert
	* @return char the converted char
	*/
	public char toHexChar(int i)
	{
		if ((0 <= i) && (i <= 9 ))
			return (char)('0' + i);
		else
			return (char)('a' + (i-10));
	}	
	
	/**
	* Convenience method to convert a byte to a hex string.
	*
	* @param data the byte to convert
	* @return String the converted byte
	*/
	public String byteToHex(byte data)
	{
		StringBuffer buf = new StringBuffer();
		buf.append(toHexChar((data>>>4)&0x0F));
		buf.append(toHexChar(data&0x0F));
		buf.append(" ");
		return buf.toString();
	}

	/**
	* Convenience method to convert a byte array to a hex string.
	*
	* @param data the byte[] to convert
	* @return String the converted byte[]
	*/
	public String bytesToHex(StringBuffer buf, byte[] data)
	{
		int bytesPerRow = 50;
		int rowCount = 0;
		for (int i = 0; i < data.length; i++)
		{
			buf.append(byteToHex(data[i]));
			rowCount++;
			if (rowCount > bytesPerRow) {
				buf.append("\r\n");
				rowCount = 0;
			}
		}
		return buf.toString();
	}	
	
	void logBytes(String caption, byte theBytes[]) {
		
		log.info("logBytes() - called;  size = " + theBytes.length);
		StringBuffer msg = new StringBuffer();
		msg.append("\r\n");
		msg.append(caption);
		msg.append("\r\nSize = ");
		msg.append(theBytes.length);
		msg.append(" > \r\n");
		msg.append(bytesToHex(msg, theBytes));
		log.info(msg.toString());
		
	}
	
	
	
	public void showBytes() {
		panelHeight = -1;
		panelWidth = -1;
		this.scaledImage = null;
		this.repaint();
	}


	private Image getOriginalImage() {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Image image = toolkit.createImage(imageBytes);
		MediaTracker mediaTracker = new MediaTracker(this);
		mediaTracker.addImage(image, 0);
		
		try
		{
			mediaTracker.waitForID(0);
		}
		catch (InterruptedException ie)
		{
			log.error("Interupted while loading image");
		}
		return(image);
	}

	
	public void renderNewScaleImage() {
		log.debug("renderNewScaleImage");
		int scale = scalePercent;
		if (imageBytes != null) {
			if (imageBytes.length <= 0) {
				log.debug("renderNewScaleImage() - image data NOT found");
			}
			else {
				log.debug("renderNewScaleImage() - image data exists");
				int scaledImageHeight = -1;
				int scaledImageWidth = -1;
				boolean needScaledImage = false;
		
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				Image image = toolkit.createImage(imageBytes);
				if ((scalePercent != 100) || (getFixedHeight() > 0) || (getFixedWidth() > 0)) {
					needScaledImage = true;
					if (panelWidth <= 0) {
						image = getOriginalImage();
					}
	
					if ((getFixedHeight() > 0) || (getFixedWidth() > 0)) {
						if (log.isDebugEnabled()) {
							log.debug("Fixed size specified, adjusting scalePercent to reflect");
							log.debug("Fixed width = " + getFixedWidth());
							log.debug("Fixed height = " + getFixedHeight());
						}
						scaledImageHeight = getFixedHeight();
						scaledImageWidth = getFixedWidth();
						if (scaledImageHeight < 0) {
							scale = 100 * scaledImageWidth / image.getWidth(null);
						}
						if (scaledImageWidth < 0) {
							scale = 100 * scaledImageHeight / image.getHeight(null);
						}
						
					}
					else {
						scale = scalePercent;
						image = getOriginalImage();
						scaledImageHeight = (image.getHeight(null) * scale) / 100;
						scaledImageWidth = -1;
						if (log.isDebugEnabled()) {
							log.debug("setting image height based on scalePercent - Scaled image height = " + scaledImageHeight);
							log.debug("setting image width based on scalePercent - Scaled image width = " + scaledImageWidth);
						}
					}
				}
				
				this.lastRenderedScalePercent = scalePercent;	// Not scale
				if (needScaledImage) {		
					if (log.isDebugEnabled()) {
						//this.logBytes("rendering scaled image - Bytes", imageBytes);
						log.debug("rendering scaled image - Byte array size = " + imageBytes.length);
						log.debug("rendering scaled image - Scaled image height = " + scaledImageHeight);
						log.debug("rendering scaled image - Scaled image width = " + scaledImageWidth);
					}
					scaledImage = image.getScaledInstance(scaledImageWidth, scaledImageHeight, Image.SCALE_SMOOTH);
				}
				else {
					scaledImage = image;
				}
				
				MediaTracker mediaTracker = new MediaTracker(this);
				mediaTracker.addImage(scaledImage, 0);
			
				try
				{
					mediaTracker.waitForID(0);
				}
				catch (InterruptedException ie)
				{
					log.error("Interupted while loading image");
				}
		
				if (log.isDebugEnabled()) {
					log.debug("ScaledImage.height = " + scaledImageHeight);
					log.debug("ScaledImage.width = " + scaledImageWidth);
				}
				
				panelWidth = image.getWidth(null) * scale / 100; 
				panelHeight = image.getHeight(null) * scale / 100; 
				if (log.isDebugEnabled()) {
					log.debug("panelWidth = " + scaledImageWidth);
					log.debug("panelHeight = " + scaledImageHeight);
				}
				
				this.setMaximumSize(new Dimension(panelWidth, panelHeight));
				this.setMinimumSize(new Dimension(panelWidth, panelHeight));
			}
		}
	}



	public void paint(Graphics graphics) {
		if (this.lastRenderedScalePercent != this.scalePercent) {
			renderNewScaleImage();
		}	
		else if (scaledImage == null) {
			renderNewScaleImage();
		}
		graphics.drawImage(scaledImage, 0, 0, null);
	}
		


	public int getImageHeight() {
		if (scaledImage == null) 
			renderNewScaleImage();
			
		int imageHeight = scaledImage.getHeight(null);
		return((imageHeight * scalePercent) / 100);
	}
	
	public int getImageWidth() {
		if (scaledImage == null) 
			renderNewScaleImage();
		if (scaledImage != null) {
			int imageWidth = scaledImage.getWidth(null);
		
			return((imageWidth * scalePercent) / 100);
		} else {
			return(0);
		}
	}
	
	/**
	 * @return
	 */
	public int getFixedHeight() {
		return fixedHeight;
	}

	/**
	 * @param imageHeight
	 */
	public void setFixedHeight(int imageHeight) {
		this.fixedHeight = imageHeight;
		scalePercent = 100;
	}

	/**
	 * @return
	 */
	public int getFixedWidth() {
		return fixedWidth;
	}

	/**
	 * @param imageWidth
	 */
	public void setFixedWidth(int imageWidth) {
		this.fixedWidth = imageWidth;
		scalePercent = 100;
	}





}
